#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "status_enum.h"
#include "student_interface.h"
#include "student_service.h"
#include "constants.h"
#include "view.h"

#define TABLE_TOP_BORDER     CYAN "┌────────────┬──────────────────────┬────────┬──────────────┐\n" RESET
#define TABLE_HEADER_LINE    CYAN "├────────────┼──────────────────────┼────────┼──────────────┤\n" RESET
#define TABLE_ROW_LINE       CYAN "├────────────┼──────────────────────┼────────┼──────────────┤\n" RESET
#define TABLE_BOTTOM_BORDER  CYAN "└────────────┴──────────────────────┴────────┴──────────────┘\n" RESET
#define TABLE_CELL_SEPARATOR CYAN "│" RESET

#define PRINT_TABLE_ROW(col1, col2, col3, col4) \
    printf(TABLE_CELL_SEPARATOR " %-10s " TABLE_CELL_SEPARATOR " %-20s " \
           TABLE_CELL_SEPARATOR " %-6s " TABLE_CELL_SEPARATOR " %-12s " \
           TABLE_CELL_SEPARATOR "\n", col1, col2, col3, col4)

static const char *PROMPT_STUDENT_ID = "请输入学生ID: ";
static const char *PROMPT_STUDENT_NAME = "请输入学生姓名: ";
static const char *PROMPT_STUDENT_GENDER = "请输入学生性别 (男/女): ";
static const char *PROMPT_STUDENT_DOB = "请输入出生日期 (YYYY-MM-DD): ";
static const char *PROMPT_DELETE_STUDENT_ID = "请输入要删除的学生ID: ";
static const char *PROMPT_DELETE_STUDENT_NAME = "请输入要删除的学生姓名: ";
static const char *PROMPT_QUERY_STUDENT_ID = "请输入要查询的学生ID: ";
static const char *PROMPT_QUERY_STUDENT_NAME = "请输入要查询的学生姓名: ";
static const char *SUCCESS_ADD = "添加成功!";
static const char *FAILURE_ADD = "添加失败, 用户已存在!";
static const char *SUCCESS_DELETE = "学生删除成功!";
static const char *FAILURE_DELETE = "删除学生失败!";
static const char *SUCCESS_QUERY = "学生找到:";
static const char *FAILURE_QUERY = "查询学生失败!";
static const char *FAILURE_GET_ALL = "获取学生列表失败，错误代码: %d\n";



void print_status(status_t status,
                  const char *success_msg, 
                  const char *failure_msg)
{
    printf("%s\n", (status == STATUS_SUCCESS) ? success_msg : failure_msg);
}

void clear_input_buffer()
{
        int c;
        while ((c = getchar()) != '\n' && c != EOF);
}

static void get_input(const char *prompt, char *output_buffer, 
                      size_t buffer_size)
{
        assert(prompt != NULL); assert(output_buffer != NULL);

        fprintf(stdout, "%s", prompt);
        if (fgets(output_buffer, buffer_size, stdin) != NULL)
                output_buffer[strcspn(output_buffer, "\n")] = '\0';
}

static void get_student_info(student_info_t *student)
{
        get_input(PROMPT_STUDENT_ID, student->id, sizeof(student->id));
        get_input(PROMPT_STUDENT_NAME, student->name, sizeof(student->name));
        get_input(PROMPT_STUDENT_GENDER, (char *)&student->gender,
              sizeof(student->gender));
        get_input(PROMPT_STUDENT_DOB, student->dob, sizeof(student->dob));
}

static void print_table(const student_info_t *students, size_t count)
{
        printf(TABLE_TOP_BORDER);
        PRINT_TABLE_ROW("ID", "NAME", "GENDER", "DOB");
        printf(TABLE_HEADER_LINE);

        for (size_t i = 0; i < count; ++i) {
                PRINT_TABLE_ROW(students[i].id, 
                                students[i].name, 
                                (students[i].gender == 1) ? "MALE" : "FMALE", 
                                students[i].dob);

                if (i < count - 1)
                        printf(TABLE_ROW_LINE);
        }

        printf(TABLE_BOTTOM_BORDER);
}

static status_t handle_student_operation(service_student_context_t *context, 
                                         const char *prompt, 
                                         status_t (*operation_func)(
                                         service_student_context_t *, 
                                         const char *, student_info_t *),
                                         const char *success_msg, 
                                         const char *failure_msg)
{
        assert(context != NULL);
        assert(prompt != NULL);
        assert(operation_func != NULL);

        char input[MAX_NAME_SIZE];
        student_info_t info;

        get_input(prompt, input, sizeof(input));

        status_t status = operation_func(context, input, &info);

        print_status(status, success_msg, failure_msg);

        if (status == STATUS_SUCCESS)
                print_table(&info, 1);

        return status;
}

status_t view_add_student(service_student_context_t *context)
{
        assert(context != NULL);

        student_info_t student;

        get_student_info(&student);

        status_t status = service_add_student(context, &student);

        print_status(status, SUCCESS_ADD, FAILURE_ADD);

        return status;
}

status_t view_service_update_student(service_student_context_t *context)
{
        assert(context != NULL);

        char student_id[MAX_ID_SIZE];
        student_info_t updated_info;

        get_input(PROMPT_STUDENT_ID, student_id, sizeof(student_id));

        get_student_info(&updated_info);

        strncpy(updated_info.id, student_id, sizeof(updated_info.id));

        status_t status = service_update_student(context, &updated_info);

        print_status(status, "学生信息更新成功!", "学生信息更新失败!");

        return status;
}

status_t view_delete_student_id(service_student_context_t *context)
{
        return handle_student_operation(context, 
                                        PROMPT_DELETE_STUDENT_ID, 
                                        service_delete_student_id,
                                        SUCCESS_DELETE,
                                        FAILURE_DELETE);
}

status_t view_delete_student_name(service_student_context_t *context)
{
        return handle_student_operation(context, 
                                        PROMPT_DELETE_STUDENT_NAME, 
                                        service_delete_student_name,
                                        SUCCESS_DELETE,
                                        FAILURE_DELETE);
}

status_t view_query_student_id(service_student_context_t *context)
{
        return handle_student_operation(context, 
                                        PROMPT_QUERY_STUDENT_ID, 
                                        service_query_student_id,
                                        SUCCESS_QUERY,
                                        FAILURE_QUERY);
}

status_t view_query_student_name(service_student_context_t *context)
{
        return handle_student_operation(context, 
                                        PROMPT_QUERY_STUDENT_NAME, 
                                        service_query_student_name,
                                        SUCCESS_QUERY,
                                        FAILURE_QUERY);
}

status_t view_get_all_student(service_student_context_t *context)
{
        student_info_t *students = NULL;
        size_t count = 0;

        status_t status = service_get_all_student(context, &students, &count);

        if (status == STATUS_SUCCESS) {
        print_table(students, count);
        free(students);
        } else {
        printf(FAILURE_GET_ALL, status);
        }

        return status;
}

static void print_student_list(const student_info_t *students, size_t count)
{
        print_table(students, count);
}

static void show_student_menu()
{
        printf("%s", CN_STUDENT);
}

static void show_student_delete_menu()
{
        printf("%s", CN_STUDENT_DEL_MENU);
}

static void show_student_query_menu()
{
        printf("%s", CN_STUDENT_QUE_MENU);
}

static void view_delete_student(service_student_context_t *context)
{
        int choice;

        while (1) {
                clear_screen();
                show_student_delete_menu();
                scanf("%d", &choice);

                if (choice > 3 || choice < 1) {
                        clear_input_buffer();
                        printf("无效输入，请重新输入。\n");
                        continue;
                }

                clear_input_buffer();

                switch (choice) {
                        case 1: view_delete_student_id(context); return;
                        case 2: view_delete_student_name(context); return;
                        case 3: return;
                        default: printf("无效的选择，请重新输入。\n"); break;
                }
        }
}

static void view_query_student(service_student_context_t *context)
{
        int choice;

        while (1) {
                clear_screen();
                show_student_query_menu();
                scanf("%d", &choice);

                if (choice > 3 || choice < 1) {
                        clear_input_buffer();
                        printf("无效输入，请重新输入。\n");
                        continue;
                }

                clear_input_buffer();

                switch (choice) {
                        case 1: view_query_student_id(context); return;
                        case 2: view_query_student_name(context); return;
                        case 3: return;
                        default: printf("无效的选择，请重新输入。\n"); break;
                }
        }
}

int student_view()
{
        service_student_context_t context;
        student_interface_t student_interface;

        status_t init_status = service_init_student(&context, &student_interface);
        if (init_status != STATUS_SUCCESS) {
                printf("Failed to initialize student service. Error code: %d\n", 
                       init_status);
                return -1;
        }

        int choice;

        while (1) {
                show_student_menu();
                scanf("%d", &choice);
                if (choice > 7 || choice < 1) {
                        clear_input_buffer(); 
                        printf("无效输入，请重新输入。\n");
                        continue;
                }

                clear_input_buffer(); 

                switch (choice) {
                        case 1: view_add_student(&context); break;
                        case 2: view_delete_student(&context); break;
                        case 3: view_service_update_student(&context); break;
                        case 4: view_query_student(&context); break;
                        case 5: view_get_all_student(&context); break;
                        case 6: clear_screen(); return 0;
                        default: printf("无效的选择，请重新输入。\n"); break;
                }
        }

        return 0;
}
